//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

namespace Microsoft.Research.eResearch.WFServiceLibrary.SchedulerLogic
{
    using System;
    using System.Collections.Generic;
    using System.Runtime.InteropServices;
    using V1 = TaskScheduler.V1;
    using V2 = TaskScheduler;

    /// <summary>
    /// Contains all the tasks that are registered.
    /// </summary>
    public sealed class TaskCollection : IEnumerable<Task>, IDisposable
    {
        private V1.ITaskScheduler v1TaskScheduler = null;
        private V2.IRegisteredTaskCollection v2TaskCollection = null;

        /// <summary>
        /// Initializes a new instance of the <see cref="TaskCollection"/> class.
        /// </summary>
        /// <param name="taskScheduler">The task scheduler.</param>
        internal TaskCollection(V1.ITaskScheduler taskScheduler)
        {
            this.v1TaskScheduler = taskScheduler;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="TaskCollection"/> class.
        /// </summary>
        /// <param name="iTaskColl">The i task coll.</param>
        internal TaskCollection(V2.IRegisteredTaskCollection iTaskColl)
        {
            this.v2TaskCollection = iTaskColl;
        }

        /// <summary>
        /// Releases all resources used by this class.
        /// </summary>
        public void Dispose()
        {
            this.v1TaskScheduler = null;
            if (this.v2TaskCollection != null)
                Marshal.ReleaseComObject(this.v2TaskCollection);
        }

        /// <summary>
        /// Gets the collection enumerator for the register task collection.
        /// </summary>
        /// <returns>An <see cref="System.Collections.IEnumerator"/> for this collection.</returns>
        public IEnumerator<Task> GetEnumerator()
        {
            IEnumerator<Task> taskEnum = null;
            if (this.v1TaskScheduler != null)
            {
                taskEnum = new V1TaskEnumerator(this.v1TaskScheduler);
            }
            else
            {
                taskEnum = new V2TaskEnumerator(this.v2TaskCollection);
            }

            return taskEnum;
        }

        /// <summary>
        /// Returns an enumerator that iterates through a collection.
        /// </summary>
        /// <returns>
        /// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection.
        /// </returns>
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }

        internal class V1TaskEnumerator : IEnumerator<Task>, IDisposable
        {
            private V1.IEnumWorkItems wienum = null;
            private V1.ITaskScheduler m_ts = null;
            private Guid ITaskGuid = Marshal.GenerateGuidForType(typeof(V1.ITask));
            private string curItem = null;

            /// <summary>
            /// Internal constructor
            /// </summary>
            /// <param name="ts">ITaskScheduler instance</param>
            internal V1TaskEnumerator(V1.ITaskScheduler ts)
            {
                this.m_ts = ts;
                wienum = m_ts.Enum();
                this.Reset();
            }

            /// <summary>
            /// Retrieves the current task.  See <see cref="System.Collections.IEnumerator.Current"/> for more information.
            /// </summary>
            public Task Current
            {
                get { return new Task(this.m_ts.Activate(this.curItem, ref this.ITaskGuid)); }
            }

            /// <summary>
            /// Gets the current V1 task enum.
            /// </summary>
            /// <value>The I current.</value>
            internal V1.ITask ICurrent
            {
                get { return this.m_ts.Activate(this.curItem, ref this.ITaskGuid); }
            }

            /// <summary>
            /// Releases all resources used by this class.
            /// </summary>
            public void Dispose()
            {
                if (wienum != null) Marshal.ReleaseComObject(wienum);
                this.m_ts = null;
            }

            /// <summary>
            /// Gets the element in the collection at the current position of the enumerator.
            /// </summary>
            /// <value></value>
            /// <returns>
            /// The element in the collection at the current position of the enumerator.
            /// </returns>
            object System.Collections.IEnumerator.Current
            {
                get { return this.Current; }
            }

            /// <summary>
            /// Moves to the next task. See MoveNext for more information.
            /// </summary>
            /// <returns>true if next task found, false if no more tasks.</returns>
            public bool MoveNext()
            {
                IntPtr names = IntPtr.Zero;
                this.curItem = null;
                try
                {
                    uint uFetched = 0;
                    wienum.Next(1, out names, out uFetched);
                    if (uFetched == 1)
                    {
                        using (V1.CoTaskMemString name = new V1.CoTaskMemString(Marshal.ReadIntPtr(names)))
                            this.curItem = name.ToString();
                    }
                }
                catch { }
                finally
                {
                    Marshal.FreeCoTaskMem(names);
                }

                return (this.curItem != null);
            }

            /// <summary>
            /// Reset task enumeration. See Reset for more information.
            /// </summary>
            public void Reset()
            {
                this.curItem = null;
                wienum.Reset();
            }
        }

        internal class V2TaskEnumerator : IEnumerator<Task>, IDisposable
        {
            private System.Collections.IEnumerator iEnum;

            /// <summary>
            /// Initializes a new instance of the <see cref="V2TaskEnumerator"/> class.
            /// </summary>
            /// <param name="iTaskColl">The i task coll.</param>
            internal V2TaskEnumerator(V2.IRegisteredTaskCollection iTaskColl)
            {
                this.iEnum = iTaskColl.GetEnumerator();
            }

            /// <summary>
            /// Gets the element in the collection at the current position of the enumerator.
            /// </summary>
            /// <value></value>
            /// <returns>
            /// The element in the collection at the current position of the enumerator.
            /// </returns>
            public Task Current
            {
                get { return new Task((V2.IRegisteredTask)this.iEnum.Current); }
            }

            /// <summary>
            /// Releases all resources used by this class.
            /// </summary>
            public void Dispose()
            {
                this.iEnum = null;
            }

            /// <summary>
            /// Gets the element in the collection at the current position of the enumerator.
            /// </summary>
            /// <value></value>
            /// <returns>
            /// The element in the collection at the current position of the enumerator.
            /// </returns>
            object System.Collections.IEnumerator.Current
            {
                get { return this.Current; }
            }

            /// <summary>
            /// Advances the enumerator to the next element of the collection.
            /// </summary>
            /// <returns>
            /// true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the collection.
            /// </returns>
            /// <exception cref="T:System.InvalidOperationException">
            /// The collection was modified after the enumerator was created.
            /// </exception>
            public bool MoveNext()
            {
                return this.iEnum.MoveNext();
            }

            /// <summary>
            /// Sets the enumerator to its initial position, which is before the first element in the collection.
            /// </summary>
            /// <exception cref="T:System.InvalidOperationException">
            /// The collection was modified after the enumerator was created.
            /// </exception>
            public void Reset()
            {
                this.iEnum.Reset();
            }
        }

        /// <summary>
        /// Gets the number of registered tasks in the collection.
        /// </summary>
        public int Count
        {
            get
            {
                if (this.v2TaskCollection != null)
                    return this.v2TaskCollection.Count;

                int i = 0;
                V1TaskEnumerator v1te = new V1TaskEnumerator(this.v1TaskScheduler);
                while (v1te.MoveNext())
                    i++;

                return i;
            }
        }

        /// <summary>
        /// Gets the <see cref="WFServiceLibrary.SchedulerLogic.Task"/> at the specified index.
        /// </summary>
        /// <value></value>
        public Task this[int index]
        {
            get
            {
                if (this.v2TaskCollection != null)
                    return new Task(this.v2TaskCollection[++index]);

                int i = 0;
                V1TaskEnumerator v1te = new V1TaskEnumerator(this.v1TaskScheduler);
                while (v1te.MoveNext())
                    if (i++ == index)
                        return v1te.Current;
                throw new ArgumentOutOfRangeException();
            }
        }

        /// <summary>
        /// Gets the named registered task from the collection.
        /// </summary>
        /// <param name="name">The name of the registered task to be retrieved.</param>
        /// <returns>A <see cref="Task"/> instance that contains the requested context.</returns>
        public Task this[string name]
        {
            get
            {
                if (this.v2TaskCollection != null)
                    return new Task(this.v2TaskCollection[name]);

                V1TaskEnumerator v1te = new V1TaskEnumerator(this.v1TaskScheduler);
                while (v1te.MoveNext())
                    if (string.Compare(v1te.Current.Name, name, true) == 0)
                        return v1te.Current;
                throw new ArgumentOutOfRangeException();
            }
        }
    }

    /// <summary>
    /// 
    /// </summary>
    public sealed class RunningTaskCollection : IEnumerable<RunningTask>, IDisposable
    {
        private V1.ITaskScheduler v1TS = null;
        private V2.ITaskService taskSvc = null;
        private V2.IRunningTaskCollection runningTaskColl = null;

        /// <summary>
        /// Initializes a new instance of the <see cref="RunningTaskCollection"/> class.
        /// </summary>
        /// <param name="ts">The ts.</param>
        internal RunningTaskCollection(V1.ITaskScheduler ts)
        {
            this.v1TS = ts;
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="RunningTaskCollection"/> class.
        /// </summary>
        /// <param name="iService">The i service.</param>
        /// <param name="iTaskColl">The i task coll.</param>
        internal RunningTaskCollection(V2.ITaskService iService, V2.IRunningTaskCollection iTaskColl)
        {
            this.taskSvc = iService;
            this.runningTaskColl = iTaskColl;
        }

        /// <summary>
        /// Releases all resources used by this class.
        /// </summary>
        public void Dispose()
        {
            this.v1TS = null;
            this.taskSvc = null;
            if (this.runningTaskColl != null)
                Marshal.ReleaseComObject(this.runningTaskColl);
        }

        /// <summary>
        /// Gets an IEnumerator instance for this collection.
        /// </summary>
        /// <returns>An enumerator.</returns>
        public IEnumerator<RunningTask> GetEnumerator()
        {
            IEnumerator<RunningTask> taskEnumerator;

            if (this.runningTaskColl != null)
            {
                taskEnumerator = new V2RunningTaskEnumerator(this.taskSvc, this.runningTaskColl);
            }
            else
            {
                taskEnumerator = new V1RunningTaskEnumerator(this.v1TS);
            }

            return taskEnumerator;
        }

        /// <summary>
        /// Returns an enumerator that iterates through a collection.
        /// </summary>
        /// <returns>
        /// An <see cref="T:System.Collections.IEnumerator"/> object that can be used to iterate through the collection.
        /// </returns>
        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }

        internal class V1RunningTaskEnumerator : IEnumerator<RunningTask>
        {
            private TaskCollection.V1TaskEnumerator tEnum;

            /// <summary>
            /// Initializes a new instance of the <see cref="V1RunningTaskEnumerator"/> class.
            /// </summary>
            /// <param name="ts">The ts.</param>
            internal V1RunningTaskEnumerator(V1.ITaskScheduler ts)
            {
                this.tEnum = new TaskCollection.V1TaskEnumerator(ts);
            }

            /// <summary>
            /// Advances the enumerator to the next element of the collection.
            /// </summary>
            /// <returns>
            /// true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the collection.
            /// </returns>
            /// <exception cref="T:System.InvalidOperationException">
            /// The collection was modified after the enumerator was created.
            /// </exception>
            public bool MoveNext()
            {
                return this.tEnum.MoveNext();
            }

            /// <summary>
            /// Gets the element in the collection at the current position of the enumerator.
            /// </summary>
            /// <value></value>
            /// <returns>
            /// The element in the collection at the current position of the enumerator.
            /// </returns>
            public RunningTask Current
            {
                get { return new RunningTask(this.tEnum.ICurrent); }
            }

            /// <summary>
            /// Releases all resources used by this class.
            /// </summary>
            public void Dispose()
            {
                this.tEnum.Dispose();
            }

            /// <summary>
            /// Gets the element in the collection at the current position of the enumerator.
            /// </summary>
            /// <value></value>
            /// <returns>
            /// The element in the collection at the current position of the enumerator.
            /// </returns>
            object System.Collections.IEnumerator.Current
            {
                get { return this.Current; }
            }

            /// <summary>
            /// Sets the enumerator to its initial position, which is before the first element in the collection.
            /// </summary>
            /// <exception cref="T:System.InvalidOperationException">
            /// The collection was modified after the enumerator was created.
            /// </exception>
            public void Reset()
            {
                this.tEnum.Reset();
            }
        }

        internal class V2RunningTaskEnumerator : IEnumerator<RunningTask>, IDisposable
        {
            private V2.ITaskService taskSvc = null;
            private System.Collections.IEnumerator iEnum;

            /// <summary>
            /// Initializes a new instance of the <see cref="V2RunningTaskEnumerator"/> class.
            /// </summary>
            /// <param name="iService">The i service.</param>
            /// <param name="iTaskColl">The i task coll.</param>
            internal V2RunningTaskEnumerator(V2.ITaskService iService, V2.IRunningTaskCollection iTaskColl)
            {
                this.taskSvc = iService;
                this.iEnum = iTaskColl.GetEnumerator();
            }

            /// <summary>
            /// Gets the element in the collection at the current position of the enumerator.
            /// </summary>
            /// <value></value>
            /// <returns>
            /// The element in the collection at the current position of the enumerator.
            /// </returns>
            public RunningTask Current
            {
                get
                {
                    V2.IRunningTask irt = (V2.IRunningTask)this.iEnum.Current;
                    return new RunningTask(TaskService.GetTask(this.taskSvc, irt.Path), irt);
                }
            }

            /// <summary>
            /// Releases all resources used by this class.
            /// </summary>
            public void Dispose()
            {
                this.taskSvc = null;
                this.iEnum = null;
            }

            /// <summary>
            /// Gets the element in the collection at the current position of the enumerator.
            /// </summary>
            /// <value></value>
            /// <returns>
            /// The element in the collection at the current position of the enumerator.
            /// </returns>
            object System.Collections.IEnumerator.Current
            {
                get { return this.Current; }
            }

            /// <summary>
            /// Advances the enumerator to the next element of the collection.
            /// </summary>
            /// <returns>
            /// true if the enumerator was successfully advanced to the next element; false if the enumerator has passed the end of the collection.
            /// </returns>
            /// <exception cref="T:System.InvalidOperationException">
            /// The collection was modified after the enumerator was created.
            /// </exception>
            public bool MoveNext()
            {
                return this.iEnum.MoveNext();
            }

            /// <summary>
            /// Sets the enumerator to its initial position, which is before the first element in the collection.
            /// </summary>
            /// <exception cref="T:System.InvalidOperationException">
            /// The collection was modified after the enumerator was created.
            /// </exception>
            public void Reset()
            {
                this.iEnum.Reset();
            }
        }

        /// <summary>
        /// Gets the number of registered tasks in the collection.
        /// </summary>
        public int Count
        {
            get
            {
                if (this.runningTaskColl != null)
                    return this.runningTaskColl.Count;
                int i = 0;
                V1RunningTaskEnumerator v1te = new V1RunningTaskEnumerator(this.v1TS);
                while (v1te.MoveNext())
                    i++;

                return i;
            }
        }

        /// <summary>
        /// Gets the specified running task from the collection.
        /// </summary>
        /// <param name="index">The index of the running task to be retrieved.</param>
        /// <returns>A <see cref="RunningTask"/> instance.</returns>
        public RunningTask this[int index]
        {
            get
            {
                if (this.runningTaskColl != null)
                {
                    V2.IRunningTask irt = this.runningTaskColl[++index];

                    return new RunningTask(TaskService.GetTask(this.taskSvc, irt.Path + irt.Name), irt);
                }

                int i = 0;
                V1RunningTaskEnumerator v1te = new V1RunningTaskEnumerator(this.v1TS);

                while (v1te.MoveNext())
                    if (i++ == index)
                        return v1te.Current;
                throw new ArgumentOutOfRangeException();
            }
        }
    }
}
